package com.yunma.dialog.rsa;

import com.common.bean.DialogBean;
import com.common.bean.exception.LogicBusinessException;
import com.common.enu.SignatureAlgorithm;
import com.common.util.SystemHWUtil;
import com.io.hw.file.util.FileUtils;
import com.string.widget.util.RegexUtil;
import com.string.widget.util.ValueWidget;
import com.swing.component.AssistPopupTextArea;
import com.swing.dialog.DialogUtil;
import com.swing.dialog.GenericFrame;
import com.swing.dialog.toast.ToastMessage;
import org.springframework.util.Base64Utils;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.security.*;
import java.util.regex.Pattern;

/***
 * 说明<br />
 * 秘钥生成格式统一为 PKCS8
 * 秘钥展示格式默认为 Base64编码<br />
 * 加密默认使用私钥,解密默认使用公钥<br />
 * 秘钥长度支持512,1024,2048,4096,<br />
 * 推荐使用2048(支付宝推荐使用)<br />
 * 生成秘钥时的种子目前是写死的:"whuang",
 */
public class RSASwingApp {
    private JTabbedPane tabbedPane1;
    private JPanel rootPanel;
    private AssistPopupTextArea privateKeyTextArea;
    /***
     * 页签"加解密"上部分的文本框
     */
    private AssistPopupTextArea sourceTextArea1;
    private JButton encryptButton;
    private JButton decryptButton;
    /***
     * 页签"加解密"下部分的文本框
     */
    private AssistPopupTextArea resultTextArea;
    private JComboBox keyComboBox1;
    private AssistPopupTextArea publicKeyTextArea1;
    private JButton replaceButton1;
    private JPanel bottomPane;
    private JButton veryfyButton;
    private AssistPopupTextArea inputTextArea1;
    private JButton deleteQuoteButton;
    private JComboBox formatComboBox1;
    private AssistPopupTextArea remarkTa;
    private JComboBox moreOperatComboBox;
    private JButton createRsaKeyButton;
    private JComboBox keyFormatComboBox1;
    private JComboBox keyBitSizeComboBox;
    /***
     * RSA 私钥
     */
    private byte[] privateKeyBytes = null;
    /***
     * RSA 公钥
     */
    private byte[] publicKeyBytes = null;
    /***
     * swing 父组件
     */
    private Component parentComponent = null;


    public RSASwingApp() {
        initUi();//初始化界面
//        this.resultTextArea.setEditable(false);
        //加密
        encryptButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
//                String sourceTxt = getSourceInput();
                String privateKeyBase64 = getPrivateKeyBase64();
                if (ValueWidget.isNullOrEmpty(privateKeyBase64)) {
                    return;
                }
//                System.out.println("sourceTxt :" + sourceTxt);
//                System.out.println("privateKeyBase64 :" + privateKeyBase64);
                resultTextArea.setText(SystemHWUtil.EMPTY);
                try {
                    byte[] encrypted = SystemHWUtil.encryptByPrivateKeyBase64(getSourceBytes(), privateKeyBase64, "RSA");
                    String encryptedStr = Base64Utils.encodeToString(encrypted);
                    resultTextArea.setText(encryptedStr);//encryptedStr 是先 base64,在 new String()的结果
                    System.out.println("encryptedStr :" + encryptedStr);
                } catch (Exception e1) {
                    e1.printStackTrace();
                    ToastMessage.toast(e1.getMessage(), 3000, Color.RED);
                }
            }
        });

        //解密
        decryptButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                String sourceTxt = getSourceInput();
                String publicKeyBase64 = getPublicKeyBase64();
                if (ValueWidget.isNullOrEmpty(publicKeyBase64)) {
                    return;
                }
                resultTextArea.setText(SystemHWUtil.EMPTY);
                try {
                    byte[] decrypted = SystemHWUtil.decryptByPublicKeyBase64(SystemHWUtil.decodeBase64(sourceTxt), publicKeyBase64, null);
                    if (null == decrypted) {
                        ToastMessage.toast("解密失败", 3000, Color.RED);
                        return;
                    }
                    resultTextArea.setText(new String(decrypted, SystemHWUtil.CHARSET_UTF));
                    ToastMessage.toast("解密成功", 2000);
                } catch (UnsupportedEncodingException e1) {
                    e1.printStackTrace();
                    ToastMessage.toast(e1.getMessage(), 3000, Color.RED);
                } catch (LogicBusinessException e2) {
                    ToastMessage.toast(e2.getMessage(), 3000, Color.RED);
                }
            }
        });
        //对调/对换
        replaceButton1.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                String result = getResultString();
                resultTextArea.setText(getSourceInput());
                sourceTextArea1.setText(result);
            }
        });
        //校验私钥和公钥是否匹配
        veryfyButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                String publicKeyBase64 = getPublicKeyBase64();
                String privateKeyBase64 = getPrivateKeyBase64();
                if (ValueWidget.isNullOrEmpty(privateKeyBase64)) {
                    return;
                }
                if (ValueWidget.isNullOrEmpty(publicKeyBase64)) {
                    return;
                }
                byte[] keyBytes = SystemHWUtil.decodeBase64(publicKeyBase64);
                PublicKey publicKey = null;
                // 取得公钥
                try {
                    publicKey = SystemHWUtil.convert2PublicKey(keyBytes);
                } catch (Exception e3) {
                    e3.printStackTrace();
                    ToastMessage.toast(e3.getMessage(), 3000, Color.RED);
                    return;
                }

                byte[] privateKeyBytes = SystemHWUtil.decodeBase64(privateKeyBase64);
                try {
                    Key privateKey = SystemHWUtil.convert2PrivateKey(privateKeyBytes, SystemHWUtil.KEY_ALGORITHM_RSA);
                    boolean verifyResult = SystemHWUtil.verifyPrivPubKey(publicKey, privateKey);
                    if (verifyResult) {
                        ToastMessage.toast("校验成功", 2000);
                    } else {
                        ToastMessage.toast("校验失败", 3000, Color.RED);
                    }
                } catch (LogicBusinessException ex) {
                    ToastMessage.toast(ex.getMessage(), 3000, Color.RED);
                }
            }
        });
        //删除引号
        deleteQuoteButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                String inputKey = inputTextArea1.getText2();
                String result = deleteQuote(inputKey);
//                System.out.println("result :" + result);
                inputTextArea1.setText(result);
            }
        });
        //格式化私钥
        formatComboBox1.addItemListener(new ItemListener() {
            @Override
            public void itemStateChanged(ItemEvent e) {
//                System.out.println(" :" +e.getStateChange());
                if (e.getStateChange() == ItemEvent.SELECTED) {
                    String inputKey = inputTextArea1.getText2();
                    int selectedIndex = formatComboBox1.getSelectedIndex();
                    if (selectedIndex == 0) {//增加换行
                        inputTextArea1.setText(deleteQuote(inputKey));
                    } else if (selectedIndex == 1) {//删除空格和换行
                        inputTextArea1.setText(inputKey.replaceAll("[\\s]+", SystemHWUtil.EMPTY));
                    } else if (selectedIndex == 2) {
                        inputKey = formatBase64ToMultiple(inputKey);
                        inputTextArea1.setText(inputKey);
                    }
                }
            }
        });
        //"加解密"页签中的 更多操作
        moreOperatComboBox.addItemListener(new ItemListener() {
            @Override
            public void itemStateChanged(ItemEvent e) {
//                System.out.println("e :" + e);
                if (e.getStateChange() == ItemEvent.SELECTED) {
                    int selectedIndex = moreOperatComboBox.getSelectedIndex();
                    moreOperateAction(selectedIndex);
                }
            }
        });
        //更多操作
        moreOperatComboBox.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                int selectedIndex = moreOperatComboBox.getSelectedIndex();
                moreOperateAction(selectedIndex);
            }
        });

        keyBitSizeComboBox.setSelectedIndex(1);
        //生成 rsa key
        createRsaKeyButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                createRsaKeyAction();

            }
        });
        keyFormatComboBox1.addItemListener(new ItemListener() {
            @Override
            public void itemStateChanged(ItemEvent e) {
                if (e.getStateChange() == ItemEvent.SELECTED) {
                    createRsaKeyAction();
                }
            }
        });

        //设置菜单,添加菜单
//        setMenuBar();
    }

    public static void main(String[] args) {
        RSASwingApp rsaSwingApp = new RSASwingApp();
        new GenericFrame() {
            @Override
            public void layout3(Container contentPane) {
//                super.layout3(contentPane);
                this.setContentPane(rsaSwingApp.rootPanel);
                this.init33(this, false);
                this.fullScreen2(this);
            }
        }.launchFrame();

    }

    public static String formatBase64ToMultiple(String inputKey) {
        inputKey = inputKey.replaceAll("(.{64})", "$1" + SystemHWUtil.CRLF);
        return inputKey;
    }

    public static String deleteQuote(String inputKey) {
        return RegexUtil.replaceAll2(inputKey, "[\\s]*\"?([^\"]+)\"[\\s]*\\+$", "$1", Pattern.MULTILINE)
                .replaceAll("[\\s]+\"", SystemHWUtil.EMPTY);
    }

    /***
     * 初始化界面
     */
    private void initUi() {
        this.sourceTextArea1.placeHolder("这是要被加解密的原文本");
        this.resultTextArea.placeHolder("使用的秘钥是\"生成秘钥\"页签中的");
    }

    private void createRsaKeyAction() {
        KeyPair kp = null;
        Integer keysize = 1024;
        switch (keyBitSizeComboBox.getSelectedIndex()) {
            case 0:
                keysize = 512;
                break;
            case 1:
                keysize = 1024;
                break;
            case 2:
                keysize = 2048;
                break;
            case 3:
                keysize = 4096;
                break;
        }

        privateKeyTextArea.setText(SystemHWUtil.EMPTY);
        publicKeyTextArea1.setText(SystemHWUtil.EMPTY);

        try {
            kp = SystemHWUtil.getKeyPair("whuang", SystemHWUtil.KEY_ALGORITHM_RSA, keysize);
        } catch (NoSuchAlgorithmException e1) {
            e1.printStackTrace();
            ToastMessage.toast(e1.getMessage(), 3000, Color.RED);
            return;
        } catch (UnsupportedEncodingException e1) {
            e1.printStackTrace();
            ToastMessage.toast(e1.getMessage(), 3000, Color.RED);
            return;
        }
        PublicKey publicKey = kp.getPublic();
        PrivateKey privateKey = kp.getPrivate();
        String publicKeyStr = null;
        String privateKeyStr = null;
        privateKeyBytes = privateKey.getEncoded();
        publicKeyBytes = publicKey.getEncoded();
        if (keyFormatComboBox1.getSelectedIndex() == 0) {// Base64编码
            publicKeyStr = SystemHWUtil.encodeBase64(publicKeyBytes);
            privateKeyStr = SystemHWUtil.encodeBase64(privateKeyBytes);
        } else {//十进制
            publicKeyStr = SystemHWUtil.toHexString(publicKeyBytes);
            privateKeyStr = SystemHWUtil.toHexString(privateKeyBytes);
        }
        privateKeyTextArea.setText(privateKeyStr);
        publicKeyTextArea1.setText(publicKeyStr);
    }

    public void setMenuBar(JDialog dialog) {
        RSAMenuListener menuListener = new RSAMenuListener();
        JMenuBar menuBar = new JMenuBar();
        JMenu fileM = new JMenu("File");
        JMenuItem save2BinaryFile = new JMenuItem("保存私钥为二进制");
        save2BinaryFile.addActionListener(menuListener);
        fileM.add(save2BinaryFile);


        JMenuItem save2Base64File = new JMenuItem("保存私钥为Base64");
        save2Base64File.addActionListener(menuListener);
        fileM.add(save2Base64File);

        menuBar.add(fileM);
        dialog.setJMenuBar(menuBar);
    }

    public void moreOperateAction(int selectedIndex) {
        String sourceTxt = getSourceInput();
        if (selectedIndex == 1) {//sha1 签名
            SignatureAlgorithm algorithm = SignatureAlgorithm.SIGNATURE_ALGORITHM_SHA1withRSA;
            String result = sign(sourceTxt, algorithm);
            System.out.println("result :" + result);
            resultTextArea.setText(result);
        } else if (selectedIndex == 2) {//sha256 签名
            SignatureAlgorithm algorithm = SignatureAlgorithm.SIGNATURE_ALGORITHM_SHA256withRSA;
            String result = sign(sourceTxt, algorithm);
            resultTextArea.setText(result);
        } else if (selectedIndex == 3) {//sha1 校验签名
//                        String privateKeyBase64 = getPrivateKeyBase64();
//                        Key privateKey = SystemHWUtil.convert2PrivateKey(SystemHWUtil.decodeBase64(privateKeyBase64), SystemHWUtil.KEY_ALGORITHM_RSA);
            SignatureAlgorithm algorithm = SignatureAlgorithm.SIGNATURE_ALGORITHM_SHA1withRSA;
            verifySign(sourceTxt, algorithm);
        } else if (selectedIndex == 4) {//sha256 校验签名
            SignatureAlgorithm algorithm = SignatureAlgorithm.SIGNATURE_ALGORITHM_SHA256withRSA;
            verifySign(sourceTxt, algorithm);
        }
    }

    public void verifySign(String sourceTxt, SignatureAlgorithm algorithm) {
        String result = getResultString();
        try {
            String publicKeyBase64 = getPublicKeyBase64();
            if (ValueWidget.isNullOrEmpty(publicKeyBase64)) {
                return;
            }
            byte[] keyBytes = SystemHWUtil.decodeBase64(publicKeyBase64);
            // 取得公钥
            PublicKey publicKey = SystemHWUtil.convert2PublicKey(keyBytes);
            boolean verifyResult = SystemHWUtil.verifySign(sourceTxt.getBytes(SystemHWUtil.CHARSET_UTF), SystemHWUtil.decodeBase64(result), publicKey, algorithm);
            if (verifyResult) {
                ToastMessage.toast("校验签名成功", 2000);
            } else {
                ToastMessage.toast("校验签名失败", 3000, Color.RED);
            }
        } catch (LogicBusinessException e2) {
            ToastMessage.toast(e2.getMessage(), 3000, Color.RED);
        } catch (UnsupportedEncodingException e1) {
            e1.printStackTrace();
        } catch (Exception e1) {
            e1.printStackTrace();
        }
    }

    public String getPublicKeyBase64() {
        String pubKeyTxt = publicKeyTextArea1.getText2();
        /*if (ValueWidget.isNullOrEmpty(pubKeyTxt)) {
            ToastMessage.toast("公钥为空,请检查\"生成秘钥\"页签", 3000, Color.RED);
            return null;
        }*/
        String errorParam = "公钥";
        if (checkKeyNull(pubKeyTxt, errorParam)) return null;
        return SystemHWUtil.deleteAllCRLF(pubKeyTxt);
    }

    public String getResultString() {
        return resultTextArea.getText2();
    }

    public String sign(String sourceTxt, SignatureAlgorithm algorithm) {
        String result = null;
        try {
            String privateKeyBase64 = getPrivateKeyBase64();
            Key privateKey = SystemHWUtil.convert2PrivateKey(SystemHWUtil.decodeBase64(privateKeyBase64), SystemHWUtil.KEY_ALGORITHM_RSA);

            byte[] signResult = SystemHWUtil.sign(sourceTxt.getBytes(SystemHWUtil.CHARSET_UTF), (PrivateKey) privateKey, algorithm);
            result = Base64Utils.encodeToString(signResult);

        } catch (UnsupportedEncodingException e1) {
            e1.printStackTrace();
        } catch (Exception e1) {
            e1.printStackTrace();
        }
        return result;
    }

    public String getPrivateKeyBase64() {
        String privateText = privateKeyTextArea.getText2();
        String errorParam = "私钥";
        if (checkKeyNull(privateText, errorParam)) return null;
        return SystemHWUtil.deleteAllCRLF(privateText);
    }

    public boolean checkKeyNull(String privateText, String errorParam) {
        if (ValueWidget.isNullOrEmpty(privateText)) {
            ToastMessage.toast(errorParam + "为空,请检查\"生成秘钥\"页签", 3000, Color.RED);
            this.tabbedPane1.setSelectedIndex(1);
            return true;
        }
        return false;
    }

    /***
     * 页签"加解密"上部分的文本框
     * @return
     */
    public String getSourceInput() {
        return sourceTextArea1.getText2();
    }

    /***
     * sourceTextArea1<br />
     * 页签"加解密"上部分的文本框
     * @return
     */
    public byte[] getSourceBytes() {
        try {
            return getSourceInput().getBytes(SystemHWUtil.CHARSET_UTF);
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return null;
    }

    public JPanel getRootPanel() {
        return rootPanel;
    }

    public void setParentComponent(Component parentComponent) {
        this.parentComponent = parentComponent;
    }

    class RSAMenuListener implements ActionListener {
        /***
         * 记录上次选择的文件,便于操作
         */
        private File selectedFile;

        @Override
        public void actionPerformed(ActionEvent event) {
            String command = event.getActionCommand();
            boolean toSave = false;
            boolean isBase64 = false;
            if (command.equals("保存私钥为Base64")) {
                toSave = true;
                isBase64 = true;
            } else if (command.equals("保存私钥为二进制")) {
                toSave = true;
                isBase64 = false;
            }
            if (toSave) {
                if (ValueWidget.isNullOrEmpty(privateKeyBytes)) {
//                    ToastMessage.toast("您还没有生成私钥", 3000, Color.RED);
//                    return;
                    if (ValueWidget.isNullOrEmpty(privateKeyTextArea.getText2())) {
                        ToastMessage.toast("您还没有生成私钥", 3000, Color.RED);
                        return;
                    }
                    privateKeyBytes = SystemHWUtil.decodeBase64(privateKeyTextArea.getText2());
                }
                if (ValueWidget.isNullOrEmpty(privateKeyBytes)) {
                    ToastMessage.toast("您还没有生成私钥", 3000, Color.RED);
                    return;
                }
                DialogBean dialogBean = DialogUtil.showSaveDialog(null, RSASwingApp.this.parentComponent, selectedFile);
                selectedFile = dialogBean.getSelectedFile();
                if (isBase64) {// Base64编码
                    String inputKey = formatBase64ToMultiple(SystemHWUtil.encodeBase64(privateKeyBytes));
                    FileUtils.writeToFile(selectedFile, inputKey, false);
                } else {//二进制
                    try {
                        FileUtils.writeBytesToFile(privateKeyBytes, selectedFile);
                    } catch (IOException e) {
                        ToastMessage.toast(e.getMessage(), 3000, Color.RED);
                        e.printStackTrace();
                    }
                }
            }
        }
    }
}
